package Askgene::File;

use warnings;
use strict;

use Carp;
use Path::Class::File;
use Moose;

use overload q{""} => sub { shift->as_string }, fallback => 1;

=head1 NAME

Askgene::File - Askgene file manipulation

=head1 SYNOPSIS
    
    my $file = Askgene::File->new( name => [qw| path to file |]);
    $file->create;
    my $filename = $file->as_string;
    my $data = "hello world!\n";
    $file->set_data($data);
    print qq{wrote "${data}" created file '${filename}'};

=head1 DESCRIPTION

Askgene::File represents files used by Askgene on the local filesystem.
It provides features such as error handling and automatic temporary file
cleanup.

=head1 ATTRIBUTES

=head2 PUBLIC

=head2 $file->path

=head2 $file->path(['path', 'to', 'file'])

Returns an arrayref representing the file path. The path can be changed by
passing a new arrayref.

=cut

has path =>
  ( isa => 'ArrayRef', is => 'rw', required => 0, default => sub { [] } );

=head2 $file->is_temp

Returns true if the file is temporary. Temporary files are deleted when its
corresponding object is DESTROY'ed.

=cut

has is_temp => ( isa => 'Bool', is => 'rw', required => 0, default => 0 );

=head2 PRIVATE

=head2 $self->pcf_obj

=head2 $self->pcf_obj(Path::Class::File->new)

Contains the underlying L<Path::Class::File> object which implements the
low-level file manipulation.

=cut

has pcf_obj => ( isa => 'Path::Class::File', is => 'rw', required => 0 );

=head1 METHODS

=head2 PUBLIC

=head2 $file->as_string

Returns a string representing the filename on the local filesystem.

=cut

sub as_string {
    my $pcf_obj = shift->pcf_obj or return;
    return $pcf_obj->stringify;
}

=head2 $file->exists

Returns true if the file exists on the local filesystem.

=cut

sub exists {    ## no critic
    my ($self) = @_;
    my $pcf_obj = $self->pcf_obj;
    return if !$pcf_obj;
    return $pcf_obj->stat ? 1 : ();
}

=head2 $file->create

Creates a file on the local filesystem using the settings found in $file

=cut

sub create {
    my ($self) = @_;

    # don't create if file already exists
    return if $self->exists;

    # initialize Path::Class::File object
    my @path;
    if ( !( @path = @{ $self->path } ) ) {
        confess q{can't create file without a filename};
    }
    my $pcf_obj = Path::Class::File->new(@path);

    $self->pcf_obj($pcf_obj)->touch;
    return 1;
}

=head2 $file->set_data($data);

Writes $data to the file. Creates file if it doesn't exist. Clobbers existing
data.

=cut

sub set_data {
    my ( $self, $data ) = @_;
    my $fh = $self->pcf_obj->open('w');
    print {$fh} $data or confess("couldn't write to file '${self}': $!");
    return 1;
}

=head2 $file->slurp

Reads the entire file into a scalar.

=cut

sub slurp {
    my ($self) = @_;
    return $self->pcf_obj->slurp;
}

sub DESTROY {
    my ($self) = @_;
    if ( $self->is_temp ) {
        $self->pcf_obj->remove;
    }
    return;
}

1;
